﻿using CinemaMaestro.BusinessLayer.Contracts;
using CinemaMaestro.DataLayer.Contracts;
using CinemaMaestro.DataLayer.Contracts.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CinemaMaestro.BusinessLayer
{
    public class Screenings : BusinessObjectBase, IScreenings
    {
        public Screenings(IUnitOfWork uow)
            : base(uow)
        { }

        public bool Create(Screening screeningToInsert)
        {
            using (var transaction = _uow.BeginTransaction())
            {
                var screeningsOnDayinRoom = Read()
                .Where(x => x.Room.Id == screeningToInsert.Room.Id).AsEnumerable()
                .Where(x => (x.StartDate.Date == screeningToInsert.StartDate.Date || x.EndDate.Date == screeningToInsert.StartDate.Date)).ToList();

                var day = screeningToInsert.StartDate.Date;
                var movie = screeningToInsert.Movie;

                var availableTimeSlots = new List<TimeSpan>();

                for (int i = 0; i < 24; i++)
                {
                    DateTime time;

                    time = new DateTime(day.Year, day.Month, day.Day, i, 0, 0);

                    var endTime = time.AddMinutes(movie.Duration);

                    bool found = false;
                    foreach (var screening in screeningsOnDayinRoom)
                    {

                        if ((time >= screening.StartDate && time <= screening.EndDate)
                            || (endTime >= screening.StartDate && endTime <= screening.EndDate))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        availableTimeSlots.Add(time.TimeOfDay);
                    }
                }

                var isTimeSlotAvailable = availableTimeSlots.Any(x => x.Hours == screeningToInsert.StartDate.Hour);

                if (isTimeSlotAvailable)
                {
                    var createdScreening = _uow.ScreeningRepository.Create(screeningToInsert);
                    _uow.SaveChanges();
                    transaction.Commit();
                    return true;
                }
                return false;
            }
        }

        public bool Delete(int id)
        {
            var deleted = _uow.ScreeningRepository.Delete(id);
            _uow.SaveChanges();
            return deleted;
        }

        public IQueryable<Screening> Read()
        {
            return _uow.ScreeningRepository.Read();
        }

        public bool Update(Screening entity)
        {
            using (var transaction = _uow.BeginTransaction())
            {
                var screeningsOnDayinRoom = Read()
                .Where(x => x.Room.Id == entity.Room.Id).AsEnumerable()
                .Where(x => (x.StartDate.Date == entity.StartDate.Date || x.EndDate.Date == entity.StartDate.Date)).ToList();

                var day = entity.StartDate.Date;
                var movie = entity.Movie;

                var availableTimeSlots = new List<TimeSpan>();

                for (int i = 0; i < 24; i++)
                {
                    DateTime time;

                    time = new DateTime(day.Year, day.Month, day.Day, i, 0, 0);

                    var endTime = time.AddMinutes(movie.Duration);

                    bool found = false;
                    foreach (var screening in screeningsOnDayinRoom)
                    {

                        if ((time >= screening.StartDate && time <= screening.EndDate)
                            || (endTime >= screening.StartDate && endTime <= screening.EndDate))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        availableTimeSlots.Add(time.TimeOfDay);
                    }
                }

                var isTimeSlotAvailable = availableTimeSlots.Any(x => x.Hours == entity.StartDate.Hour);

                if (isTimeSlotAvailable)
                {
                    _uow.ScreeningRepository.Update(entity);
                    _uow.SaveChanges();
                    transaction.Commit();
                    return true;
                }
                return false;
            }
        }

        public bool ScreeningHasRelationWithLanguage(int languageId)
        {
            bool hasRelation = Read().Any(x => x.Language.Id == languageId);
            return hasRelation;
        }

        public bool ScreeningHasRelationWithRoom(int roomId)
        {
            bool hasRelation = Read().Any(x => x.Room.Id == roomId);
            return hasRelation;
        }

        public bool ScreeningHasRelationWithMovie(int movieId)
        {
            bool hasRelation = Read().Any(x => x.Movie.Id == movieId);
            return hasRelation;
        }
    }
}
